type EventHandler = (...args: any[]) => void;

export class EventEmitter {
    private events: Map<string, Set<EventHandler>>;
    
    constructor() {
        this.events = new Map();
    }
    
    /**
     * Add an event listener
     */
    public on(event: string, handler: EventHandler): void {
        if (!this.events.has(event)) {
            this.events.set(event, new Set());
        }
        this.events.get(event)!.add(handler);
    }
    
    /**
     * Add an event listener that will be called only once
     */
    public once(event: string, handler: EventHandler): void {
        const onceHandler = (...args: any[]) => {
            this.off(event, onceHandler);
            handler(...args);
        };
        this.on(event, onceHandler);
    }
    
    /**
     * Remove an event listener
     */
    public off(event: string, handler: EventHandler): void {
        const handlers = this.events.get(event);
        if (handlers) {
            handlers.delete(handler);
            if (handlers.size === 0) {
                this.events.delete(event);
            }
        }
    }
    
    /**
     * Remove all listeners for an event
     */
    public removeAllListeners(event?: string): void {
        if (event) {
            this.events.delete(event);
        } else {
            this.events.clear();
        }
    }
    
    /**
     * Get all listeners for an event
     */
    public listeners(event: string): EventHandler[] {
        return Array.from(this.events.get(event) || []);
    }
    
    /**
     * Get the number of listeners for an event
     */
    public listenerCount(event: string): number {
        return this.events.get(event)?.size || 0;
    }
    
    /**
     * Emit an event
     */
    public emit(event: string, ...args: any[]): boolean {
        const handlers = this.events.get(event);
        if (!handlers) return false;
        
        // Create a copy of the handlers set to avoid issues if handlers are removed during iteration
        const handlersCopy = new Set(handlers);
        for (const handler of handlersCopy) {
            try {
                handler(...args);
            } catch (error) {
                console.error(`Error in event handler for ${event}:`, error);
            }
        }
        
        return true;
    }
    
    /**
     * Check if an event has any listeners
     */
    public hasListeners(event: string): boolean {
        return this.events.has(event) && this.events.get(event)!.size > 0;
    }
    
    /**
     * Get all event names that have listeners
     */
    public eventNames(): string[] {
        return Array.from(this.events.keys());
    }
    
    /**
     * Remove an event listener
     */
    public removeListener(event: string, handler: EventHandler): void {
        const handlers = this.events.get(event);
        if (handlers) {
            handlers.delete(handler);
            if (handlers.size === 0) {
                this.events.delete(event);
            }
        }
    }
} 